#include "SceneManager.h"

/////////////////////////////////////////////////////////
////
//// Scene Manager Related Stuff
////

Scene::Scene()
{
		////////////////////
		//init the matrix stack
		m_MatrixStack = NULL;
		if(D3DXCreateMatrixStack(0, &m_MatrixStack) != S_OK)
		{
			assert(0 && "failed to init the matrix stack.");
		}
		m_RootSceneNode = SceneNodePtr(RE_NEW RootSceneNode);
		Scene::VBuildAndSetProjMatrix(0.78539f, 1.333f, 0.1f, 1000.0f);
		Scene::VBuildAndSetViewMatrix();
		//build default camera (empty)
		m_Camera = SceneNodePtr(RE_NEW CameraNode(Vec3(3,3,3), Quaternion(0,D3DX_PI / 4,0,1)));
};
bool Scene::VOnRender()
{
	if(NULL == m_Camera.get())
	{
		return false;
	}
		//update view matrix
	CameraNode * Camera = dynamic_cast<CameraNode*>(m_Camera.get());
	//Scene::BuildAndSetViewMatrix(Camera->m_Props.m_ToWorld.GetPosition(), Camera->m_Props.m_ToWorld.GetPosition() + Camera->m_Props.m_ToWorld.GetForward());
	VBuildAndSetViewMatrix(Vec3(3,3,3), Vec3(0,0,0));
	if(m_RootSceneNode->VOnRender(this))
	{
		return true;
	}
	return false;
}

void Scene::VPushAndSetMatrix(const Mat4x4 & ToWorld)
{
	m_MatrixStack->Push();
	m_MatrixStack->MultMatrixLocal(&ToWorld);
	Mat4x4 world = static_cast<Mat4x4>(*m_MatrixStack->GetTop());
	RandomEngineApp::Get()->GetRenderer()->VSetWorldMatrix(&world);
};

void Scene::VPopMatrix()
{
	m_MatrixStack->Pop();
}


void Scene::VBuildAndSetProjMatrix(float FOV , float AspectRatio , float ClippingPlane_near , float ClippingPlane_far )
{
	Mat4x4 matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, FOV, AspectRatio, ClippingPlane_near, ClippingPlane_far );
	RandomEngineApp::Get()->GetRenderer()->VSetProjMatrix(&matProj);
}

void Scene::VBuildAndSetViewMatrix(const Vec3 & Position, const Vec3 & LookAt, const Vec3 & WorldUpVector)
{
	Mat4x4 matView;
    D3DXMatrixLookAtLH( &matView, &Position, &LookAt, &WorldUpVector );
	RandomEngineApp::Get()->GetRenderer()->VSetViewMatrix(&matView);
}

bool Scene::VOnUpdate(float fTime)
{
	return m_RootSceneNode->VOnUpdate(fTime);

}
void Scene::VAddSceneNode(const SceneNodePtr node)
{
	//this shoud actually check where shoud it attach the node but for now it will just get added to the root;
	VGetRootSceneNode()->VAddChild(node);
	m_scenenodes[node->VGetId()] = node;
}
ISceneNode* Scene::VGetNodeById(const ActorId id)
{
	SceneNodeMap::iterator i = m_scenenodes.find(id);
	if(i == m_scenenodes.end())
	{
		assert(0 && "No node with this id.");
		return NULL;
	}
	return i->second.get();
}